//Serão consideradas palavras apenas as sequencias de caracteres compostas por letras. Serao consideradas frases o conjunto de palavras delimitadas por pontos ou /n
//Os caracteres " ,./?'\";:|^-!$#@`~*&%)(+=_}{][\n\t\\" serão considerados separadores de palavra. Os caracteres ".?;:!\n\t\\" serao considerados separadores de frase.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <omp.h>

//Definicao do tamanho de cada palavra e de cada bloco de leitura
#define BLOCK_SIZE 300
#define PHRASE_SIZE 300
#define WORD_SIZE 300

void strRev(char *);
void strUpper(char *);
int chkPal(char *);
void removeSpaces (char *); 

int main(int argc, char *argv[])
{
	//Variáveis
	int cont = 0, cont2 = 0, i, n = 0, m = 0;
	double t0, tf, nT = 0.0, wT = 0.0, rT = 0.0;
	char bufferFrase[BLOCK_SIZE], bufferPalavra[BLOCK_SIZE], **palavras, **frases;
	FILE *fpin;

	//Abre o arquivo e vai até o final para determinar o tamanho
	long fileSize=0;
	if((fpin=fopen(argv[1], "r")) != NULL)
	{
		fseek(fpin, 0, SEEK_END);
		fileSize = ftell(fpin);
	}
	else
	{	
		return -1;
	}
	fclose(fpin);
	
	//Abre o arquivo
	if((fpin=fopen(argv[1], "r")) == NULL)
	{	
		printf("Erro ao abrir o arquivo %s.\n", argv[1]);
		return -1;
	}
	
	//Abre o arquivo onde serão registrados os palindromos
	FILE *fpout;
	char outFileName[50];
	sprintf(outFileName,"out.txt");
	if((fpout=fopen(outFileName, "w")) == NULL)
	{	
		printf("Erro ao abrir o arquivo %s.\n", outFileName);
		return -1;
	}
	
	//Pega um bloco de texto, conta tempo
	//Faz parse (pega cada palavra e frase), conta tempo
	//Checa palindromos, conta tempo
	
	//Abre o arquivo onde serão registrados os palindromos
	long iter = 0;
	double tot0 = omp_get_wtime();
	while(!feof(fpin))
	{	
		//Le bloco
		fread(bufferFrase, BLOCK_SIZE, 1, fpin);
		strcpy(bufferPalavra, bufferFrase);
		//Parseia e processa palavras
		char* token = strtok(bufferPalavra, " ,./?'\";:|^-!$#@`~*&%)(+=_}{][\n\t\r\\");
		while(token != NULL)
		{
			char* tok = strdup(token);
			t0 = omp_get_wtime();
			if(chkPal(tok))
			{		
				tf = omp_get_wtime();
				rT += tf - t0;
				fprintf(fpout,"%s\n", tok);
				cont++;
			}
			token = strtok(NULL, " ,./?'\";:|^-!$#@`~*&%)(+=_}{][\n\t\r\\");
		}
		free(token);
		
		//Parseia e processa frases
		token = strtok(bufferFrase, ".?;:!()[]{}\n\t\r");
		while(token != NULL)
		{
			char* tok = strdup(token);
			t0 = omp_get_wtime();
			removeSpaces(tok);
			if(chkPal(tok))
			{		
				tf = omp_get_wtime();
				wT += tf - t0;
				fprintf(fpout,"%s\n", tok);
				cont2++;
			}
			token = strtok(NULL, ".?;:!()[]{}\n\t\r");
		}
		free(token);
		
		//Prepara a posicao que sera feita a proxima leitura
		iter++;	
		if ((iter*BLOCK_SIZE) > fileSize) //Testa se o proximo seek vai pra fora do arquivo
		{
			break;
		}
		else
		{
			fseek(fpin, (iter*BLOCK_SIZE), SEEK_SET); //Pula para o proximo lugar que sera lido
		}
	}
	double totF = omp_get_wtime();
	printf("Numero de palavras palindromo: %d\nNumero de frases palindromo: %d\nTempo total: %lf\nTempo palavra: %lf\nTempo frase: %lf\n",cont,cont2,(totF-tot0),rT,wT);
	fclose(fpin);
	fclose(fpout);
	return 0;
}

void strRev(char *str)
{
	//Baseado no algoritmo XOR SWAP
	// X := X XOR Y
	// Y := X XOR Y
	// X := X XOR Y
	char *p1, *p2;
	for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) //p1 vai do começo até o meio da string e p2 vai do fim até o meio
	{
		//Swap
		*p1 ^= *p2;
		*p2 ^= *p1;
		*p1 ^= *p2;
	}
}

int chkPal(char *str)
{
	char aux[PHRASE_SIZE];
	//Inverte a palavra. Se for igual a palavra nao invertida, e palíndromo
	if(strlen(str) > 1)
	{
		strUpper(str);
		strcpy(aux,str);
		strRev(aux);
		if(strcmp(str,aux) == 0 )
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	else
	{ 
		return 0;
	}
}

void strUpper(char *str)
{
	//Passa a palavra para maiuscula, eliminando acentos, etc.
	int i;
	for (i = 0 ; i < strlen(str) ; i++)
	{
		str[i] = toupper(str[i]);
	}
}

//Para testar se uma frase e palindromo, remover todos os espacos em branco.
void removeSpaces (char *str) 
{
    char *src = str;
    char *dst = src;
    while (*src != '\0') 
	{
        if (*src != ' ')
		{
            *dst++ = *src;
		}
        src++;
    }
    *dst = '\0';
}
